<?xml version="1.0" encoding="UTF-8"?><d:tdl xmlns="http://www.w3.org/1999/xhtml" xmlns:b="http://www.backbase.com/2006/btl" xmlns:bb="http://www.backbase.com/2006/client"  xmlns:d="http://www.backbase.com/2006/tdl" >

	<d:namespace name="http://www.backbase.com/2006/btl">

		<d:uses element="labelImplementor" src="../label/label.xml"/>
		<d:uses element="dimensionElement containerElement" src="../visualElement/visualElement.xml"/>

		<d:element name="balloonBase" extends="b:dimensionElement b:containerElement b:labelImplementor" abstract="true">
			

			<d:resource type="text/css"><![CDATA[
				.btl-balloon {
					display: none;
					position: absolute;
				}
				.btl-balloon-open {
					display: block;
				}
				.btl-balloon-close-button {
					cursor: default;
					overflow: hidden;
				}
			]]></d:resource>

			<d:resource type="text/javascript"><![CDATA[
				btl.balloon = {};

				/**
				 * Shows balloon.
				 * @param oBalloon {controller object} - balloon element to show.
				 * @return {boolean} - true or false depending on the operation success.
				 */
				btl.balloon._show = function(oBalloon) {
					var sMode = oBalloon.getAttribute('mode');
					var oParent = oBalloon.getProperty('parentNode');
					if(oParent){
						bb.html.addClass(oBalloon.viewNode, 'btl-balloon-open');
						// clean up any classes that have been set
						bb.html.removeClass(oBalloon.viewNode, [
							'btl-balloon-top-left', 'btl-balloon-top-center',
							'btl-balloon-top-right', 'btl-balloon-bottom-right',
							'btl-balloon-bottom-center', 'btl-balloon-bottom-left'
						]);
						var aCoord = bb.html.getBoxObject(oParent.viewNode);

						var parentX = aCoord.left;
						var parentY = aCoord.top;
						var parentWidth = aCoord.width;
						var parentHeight = aCoord.height;
						if(!parentHeight || !parentWidth){ // fix for startup
							oBalloon.addEventListener('DOMNodeInsertedIntoDocument',
							function(event){
								oBalloon.removeEventListener('DOMNodeInsertedIntoDocument', arguments.callee, false);
								oBalloon.setAttribute('open', 'true'); //reset
							}
							,false);
							oBalloon.removeAttribute('open'); //will set later, on reflow
						}
						var balloonWidth = bb.html.getBoxObject(oBalloon.viewNode).width;
						var balloonHeight = bb.html.getBoxObject(oBalloon.viewNode).height;
						var scrollLeft = bb.viewport.scrollLeft, scrollTop = bb.viewport.scrollTop;
						var scrollWidth = bb.viewport.scrollWidth, scrollHeight = bb.viewport.scrollHeight;

						var iArrowCorrection = 8;

						var top, left;

						switch(sMode){
							case 'top-left':
								bb.html.addClass(oBalloon.viewNode, 'btl-balloon-top-left');
								top = parentY - balloonHeight - iArrowCorrection;
								left = parentX;
								break;
							case 'top-center':
								top = parentY - balloonHeight - iArrowCorrection;
								left = parentX + parentWidth/2 - balloonWidth/2;
								bb.html.addClass(oBalloon.viewNode, 'btl-balloon-top-center');
								break;
							case 'top-right':
								bb.html.addClass(oBalloon.viewNode, 'btl-balloon-top-right');
								top = parentY - balloonHeight - iArrowCorrection;
								left = parentX + parentWidth - balloonWidth;
								break;
							case 'bottom-right':
								bb.html.addClass(oBalloon.viewNode, 'btl-balloon-bottom-right');
								top = parentY + parentHeight + iArrowCorrection;
								left = parentX + parentWidth - balloonWidth;
								break;
							case 'bottom-center':
								bb.html.addClass(oBalloon.viewNode, 'btl-balloon-bottom-center');
								top = parentY + parentHeight + iArrowCorrection;
								left = parentX + parentWidth/2 - balloonWidth/2;
								break;
							case 'bottom-left':
								bb.html.addClass(oBalloon.viewNode, 'btl-balloon-bottom-left');
								top = parentY + parentHeight + iArrowCorrection;
								left = parentX;
								break;
						}

						if(!top || 0 > top) top = 0;
						else if(top + balloonHeight > scrollTop + scrollHeight) top = scrollTop + scrollHeight - balloonHeight;

						if(!left || 0 > left) left = 0;
						else if(left + balloonWidth > scrollLeft + scrollWidth) left = scrollLeft + scrollWidth - balloonWidth;

						oBalloon.viewNode.style.top = top + 'px';
						oBalloon.viewNode.style.left = left + 'px';

						var sTimeout = oBalloon.getAttribute('timeout');
						if(sTimeout){
							var iTimeout = bb.time.getClockValue(sTimeout);
							setTimeout(
								function(){
									if(oBalloon._){
										oBalloon.removeAttribute('open');
									}
								}
								,
								iTimeout
							)
						}
						return true;
					}
					return false;
				};

				/**
				 * Hides the balloon.
				 * @param oBalloon {controller object} - balloon to hide.
				 * @return {boolean} - true or false depending on the operation success.
				 */
				btl.balloon._hide = function(oBalloon) {
					bb.html.removeClass(oBalloon.viewNode, 'btl-balloon-open');
				};
			]]></d:resource>

			<d:attribute name="open" default="false">
				
				<d:changer type="text/javascript"><![CDATA[
					if(btl.isTrueValue(name, value)){
						btl.balloon._show(this);
					} else {
						btl.balloon._hide(this);
					}
				]]></d:changer>
			</d:attribute>

			<d:attribute name="timeout">
				
			</d:attribute>

			<d:attribute name="mode" default="top-right">
				
			</d:attribute>

			<d:destructor type="text/javascript"><![CDATA[
				if(this.viewNode.parentNode)
					this.viewNode.parentNode.removeChild(this.viewNode);
			]]></d:destructor>

			<d:handler event="DOMNodeInsertedIntoDocument" type="text/javascript"><![CDATA[
				document.body.appendChild(this.viewNode);

				// this is done here so even dinamically created element with
				// "open" attribute set to true will be shown when put into document
				if (btl.isTrueValue("open", this.getAttribute("open"))) {
					btl.balloon._show(this);
				}
			]]></d:handler>
		</d:element>
	</d:namespace>
</d:tdl>